package org.lemon.cla.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.lemon.cla.enums.HttpStatusEnum;
import org.lemon.cla.dto.response.ResponseResult;
import org.lemon.cla.dto.request.BookCreateRequest;
import org.lemon.cla.dto.request.BookUpdateRequest;
import org.lemon.cla.dto.request.BookSearchRequest; // 导入查询请求DTO
import org.lemon.cla.pojo.Book;
import org.lemon.cla.enums.BookStatusEnum;
import org.lemon.cla.service.IBookService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;

import java.util.List; // 尽管不再直接返回List，但可能因其他业务逻辑或遗留代码保留
import java.util.Optional; // 导入Optional

import org.lemon.cla.exception.BusinessException; // 导入自定义业务异常


@RestController
@RequestMapping("/api/books")
@Tag(name = "图书管理", description = "提供图书信息的 CRUD 和查询接口")
public class BookController {

    @Autowired
    private IBookService bookService;

    @Operation(summary = "获取所有图书", description = "分页获取所有图书列表。")
    @GetMapping // 统一的 GET 接口，用于获取所有（无筛选）的分页列表
    public ResponseResult<IPage<Book>> getAllBooks(
            @Parameter(description = "页码", example = "1") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页数量", example = "10") @RequestParam(defaultValue = "10") Integer pageSize) {
        Page<Book> page = new Page<>(pageNum, pageSize);
        // 调用统一的搜索方法，传入空的请求对象，表示无筛选
        IPage<Book> bookPage = bookService.searchBooksByConditions(page, new BookSearchRequest());
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), bookPage);
    }

    @Operation(summary = "根据ID获取图书", description = "根据图书ID获取图书详情。")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取图书"),
            @ApiResponse(responseCode = "404", description = "图书未找到")
    })
    @GetMapping("/{id}")
    public ResponseResult<Book> getBookById(
            @Parameter(description = "图书ID", required = true, example = "1") @PathVariable Long id) {
        // 使用Optional简化null检查，如果未找到则抛出业务异常
        return Optional.ofNullable(bookService.getById(id))
                .map(book -> ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), book))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "图书未找到。")); // 抛出BusinessException
    }

    @Operation(summary = "创建新图书", description = "创建一个新的图书记录。")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "图书创建成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误 (如校验失败，请检查请求体)"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping
    @PreAuthorize("hasRole('管理员')") // 只有拥有 'ROLE_管理员' 角色的用户才能访问
    public ResponseResult<Book> createBook(
            @Parameter(description = "图书创建请求对象 (无需传入 bookId, availableCopies 和 status)", required = true)
            @RequestBody @Valid BookCreateRequest request) {

        Book book = new Book();
        BeanUtils.copyProperties(request, book);

        // 使用Optional处理availableCopies的默认值
        book.setAvailableCopies(Optional.ofNullable(request.getTotalCopies()).orElse(0));
        book.setStatus(BookStatusEnum.AVAILABLE); // 默认可借状态

        boolean success = bookService.save(book);
        if (!success) { // 如果保存操作返回false但未抛出异常
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "图书创建失败，请稍后重试。"); // 抛出BusinessException
        }
        return ResponseResult.success(HttpStatusEnum.CREATED.getCode(), HttpStatusEnum.CREATED.getMessage(), book);
    }

    @Operation(summary = "更新图书", description = "根据图书ID更新图书信息。")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "图书更新成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误或没有需要更新的字段"),
            @ApiResponse(responseCode = "404", description = "图书未找到"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误"),
            @ApiResponse(responseCode = "409", description = "ISBN已存在")
    })
    @PutMapping("/{id}")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<Book> updateBook(
            @Parameter(description = "图书ID", required = true, example = "1") @PathVariable Long id,
            @Parameter(description = "更新后的图书对象", required = true) @RequestBody @Valid BookUpdateRequest request) {

        Book existingBook = Optional.ofNullable(bookService.getById(id))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "图书未找到。")); // 如果未找到则抛出BusinessException

        // 校验ISBN唯一性：如果ISBN被修改且与现有图书的ID不同
        Optional.ofNullable(request.getIsbn())
                .filter(isbn -> !isbn.equals(existingBook.getIsbn())) // 只有当ISBN实际改变时才校验
                .ifPresent(isbn -> {
                    Optional.ofNullable(bookService.getOne(new QueryWrapper<Book>().eq("isbn", isbn)))
                            .ifPresent(conflictBook -> {
                                throw new BusinessException(HttpStatusEnum.CONFLICT.getCode(), "更新失败：ISBN已存在。"); // 抛出BusinessException
                            });
                });

        // 拷贝非空属性到现有实体，MyBatis-Plus会智能更新
        BeanUtils.copyProperties(request, existingBook);

        boolean success = bookService.updateById(existingBook);
        if (!success) { // 如果更新返回false
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "图书更新失败，请稍后重试。"); // 抛出BusinessException
        }
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), existingBook);
    }

    @Operation(summary = "删除图书", description = "根据图书ID删除图书。")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "图书删除成功"),
            @ApiResponse(responseCode = "404", description = "图书未找到"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @DeleteMapping("/{id}")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<Void> deleteBook(
            @Parameter(description = "图书ID", required = true, example = "1") @PathVariable Long id) {
        boolean success = bookService.removeById(id);
        if (!success) { // 如果删除返回false
            throw new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "图书未找到或删除失败。"); // 抛出BusinessException
        }
        return ResponseResult.success(HttpStatusEnum.NO_CONTENT.getCode(), HttpStatusEnum.NO_CONTENT.getMessage(), null);
    }

    @Operation(summary = "模糊查询图书", description = "根据ISBN、标题、状态、出版社、作者、位置进行模糊查询。")
    @PostMapping("/search") // 统一的POST /search 接口，用于所有分页和带条件的查询
    public ResponseResult<IPage<Book>> searchBooks(
            @Parameter(description = "页码", example = "1") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页数量", example = "10") @RequestParam(defaultValue = "10") Integer pageSize,
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "图书查询请求对象 (可选，用于筛选)",
                    required = false,
                    content = @Content(schema = @Schema(implementation = BookSearchRequest.class))
            ) @org.springframework.web.bind.annotation.RequestBody BookSearchRequest request) {

        Page<Book> page = new Page<>(pageNum, pageSize);

        // 使用Optional简化，确保request总是一个非null的实例
        request = Optional.ofNullable(request).orElseGet(BookSearchRequest::new);

        IPage<Book> resultPage = bookService.searchBooksByConditions(page, request);

        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), resultPage);
    }

}
